using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

using Conscript;
using Conscript.Compiler;
using Conscript.Runtime;

namespace DungeonOfDespair
{
    public class GameStatePlay
        : GameState
    {
        private GameStateType m_gameStateTypeNext;
        private ScriptManager m_scriptManager;
        private Player m_player;
        private Boss m_boss;
        private Dungeon m_dungeon;
        private int m_iPlayerHealth;
        private RectangleF m_rectPlayerHealth;
        private Sprite m_spriteHealthGreen;
        private Sprite m_spriteHealthAmber;
        private Sprite m_spriteHealthRed;
        private int m_iWinWait;

        private void DrawUserInterface(Graphics graphics)
        {
            Image imageContainer = Properties.Resources.HealthContainer;

            // colour-variant health bar
            m_rectPlayerHealth.Width = (imageContainer.Width * m_iPlayerHealth) / 100;
            Sprite spriteBack = m_iPlayerHealth < 50 ? m_spriteHealthRed : m_spriteHealthAmber;
            Sprite spriteFront = m_iPlayerHealth < 50 ? m_spriteHealthAmber : m_spriteHealthGreen;
            spriteFront.Opacity = m_iPlayerHealth < 50
                ? m_iPlayerHealth / 50.0f
                : (m_iPlayerHealth - 50.0f) / 50.0f;
            spriteBack.ClipBounds = m_rectPlayerHealth;
            spriteBack.Draw(graphics);
            spriteFront.ClipBounds = m_rectPlayerHealth;
            spriteFront.Draw(graphics);

            // health container
            graphics.DrawImage(imageContainer, 16, 16, imageContainer.Width, imageContainer.Height);

            // vials in player's possesion
            graphics.DrawImage(
                m_player.HasRedVial
                    ? Properties.Resources.VialRed
                    : Properties.Resources.VialSlot,
                500, 4, 32, 39);
            graphics.DrawImage(
                m_player.HasGreenVial
                    ? Properties.Resources.VialGreen
                    : Properties.Resources.VialSlot,
                532, 4, 32, 39);
            graphics.DrawImage(
                m_player.HasYellowVial
                    ? Properties.Resources.VialYellow
                    : Properties.Resources.VialSlot,
                564, 4, 32, 39);
            graphics.DrawImage(
                m_player.HasBlueVial
                    ? Properties.Resources.VialBlue
                    : Properties.Resources.VialSlot,
                596, 4, 32, 39);
        }

        public GameStatePlay()
        {
            m_gameStateTypeNext = GameStateType.None;
            m_scriptManager = new ScriptManager();

#if DEBUG
            m_scriptManager.DebugMode = true;
#else
            m_scriptManager.DebugMode = false;
#endif

            HostFunctionPrototype hostFunctionPrototype = null;
            hostFunctionPrototype = new HostFunctionPrototype(typeof(int), "GetRandom", typeof(int), typeof(int));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "Move", typeof(int), typeof(int));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "SetDirection", typeof(int));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "SetAutomaticDirection", typeof(bool));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(typeof(AssociativeArray), "GetPosition");
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(typeof(AssociativeArray), "GetPlayerPosition");
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype("CastSpell");
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);

            hostFunctionPrototype = new HostFunctionPrototype(null, "Player_SetActive", typeof(bool));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "Player_SetPosition", typeof(int), typeof(int));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "Player_MoveTo", typeof(int), typeof(int));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(typeof(bool), "Player_Moving");
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "Player_Say", typeof(String));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(typeof(bool), "Player_HasAllVials");
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);

            hostFunctionPrototype = new HostFunctionPrototype(null, "Boss_SetActive", typeof(bool));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "Boss_SetPosition", typeof(int), typeof(int));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "Boss_MoveTo", typeof(int), typeof(int));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(typeof(bool), "Boss_Moving");
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "Boss_Say", typeof(String));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);
            hostFunctionPrototype = new HostFunctionPrototype(null, "Boss_SpawnEnemy", typeof(String));
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);

            hostFunctionPrototype = new HostFunctionPrototype(typeof(bool), "TextWindow_IsActive");
            m_scriptManager.RegisterHostFunction(hostFunctionPrototype);

            m_player = new Player();
            m_player.X = 320;
            m_player.Y = 268;
            m_player.Direction = EntityDirection.Right;

            m_boss = new Boss();

            m_dungeon = new Dungeon(m_scriptManager, m_player, m_boss);

            m_iPlayerHealth = 0;
            m_spriteHealthGreen = new Sprite(Properties.Resources.HealthGreen);
            m_spriteHealthGreen.X = 16;
            m_spriteHealthGreen.Y = 16;
            m_spriteHealthAmber = new Sprite(Properties.Resources.HealthAmber);
            m_spriteHealthAmber.X = 16;
            m_spriteHealthAmber.Y = 16;
            m_spriteHealthRed = new Sprite(Properties.Resources.HealthRed);
            m_spriteHealthRed.X = 16;
            m_spriteHealthRed.Y = 16;
            m_rectPlayerHealth = new RectangleF(0.0f, 0.0f,
                m_spriteHealthGreen.Image.Width,
                m_spriteHealthGreen.Image.Height);

            m_iWinWait = 0;

            m_dungeon.Load();
        }

        public void OnKeyDown(object objectSender, KeyEventArgs keyEventArgs)
        {
            if (m_player.Active)
            {
                switch (keyEventArgs.KeyCode)
                {
                    case Keys.Left: m_player.Move(-640, 0); m_player.Direction = EntityDirection.Left; break;
                    case Keys.Right: m_player.Move(640, 0); m_player.Direction = EntityDirection.Right; break;
                    case Keys.Up: m_player.Move(0, -480); m_player.Direction = EntityDirection.Up; break;
                    case Keys.Down: m_player.Move(0, 480); m_player.Direction = EntityDirection.Down; break;
                }
            }
        }

        public void OnKeyUp(object objectSender, KeyEventArgs keyEventArgs)
        {
            if (m_player.Active)
            {
                switch (keyEventArgs.KeyCode)
                {
                    case Keys.Left:
                    case Keys.Right:
                    case Keys.Up:
                    case Keys.Down:
                        m_player.Move(0, 0);
                        break;
                    case Keys.Space:
                        Spells spells = m_dungeon.CurrentRoom.Spells;
                        Spell spell = new Spell(spells,
                            Properties.Resources.PlayerSpell,
                            true, 10, m_player.Direction);
                        spell.X = m_player.X;
                        spell.Y = m_player.Y - 30;
                        spells.Add(spell);
                        break;
                }
            }

            switch (keyEventArgs.KeyCode)
            {
                case Keys.Escape:
                    m_gameStateTypeNext = GameStateType.Title;
                    break;
            }
        }

        public void Update()
        {
            // cheat mode
            if (m_dungeon.Cheat)
                m_player.Health = 100;

            // ui delayed health meter
            if (m_iPlayerHealth < m_player.Health)
                ++m_iPlayerHealth;
            if (m_iPlayerHealth > m_player.Health)
                --m_iPlayerHealth;

            m_player.Update();

            if (m_boss.Active)
                m_boss.Update();

            m_dungeon.Update(m_player);

            // check for gameover state
            if (m_iPlayerHealth <= 0)
                m_gameStateTypeNext = GameStateType.GameOver;

            // check for win state
            if (m_dungeon.PortalActive)
                ++m_iWinWait;
            if (m_iWinWait > 74)
                m_gameStateTypeNext = GameStateType.GameWon;
        }

        public void Draw(Graphics graphics)
        {
            m_dungeon.Draw(graphics);

            // ui
            DrawUserInterface(graphics);

            // handle win stage
            if (m_iWinWait >= 50 && m_iWinWait < 75)
                graphics.FillRectangle(
                    new SolidBrush(Color.FromArgb((m_iWinWait - 50) * 255 / 25, 255, 255, 255)),
                    0, 0, 640, 480);
        }

        public GameStateType NextState
        {
            get { return m_gameStateTypeNext; }
        }
    }
}
